<template>
  <div
    :class="animate"
    :style="{ height: height, width: width }"
    :id="chartOption.bindingDiv"
    ref="chartDiv"
  />
</template>

<script>
import echarts from "echarts";
require("echarts/theme/macarons"); // echarts theme
import resize from "@/views/dashboard/mixins/resize";
import interactConfig from "../mixins/interactConfig";
import "../../animate/animate.css";

import { parseQueryString, fIsUrL } from "../../util/urlUtil";
import { dealWithData,testData } from "../../util/utilFun.js";
import { linkChart } from "../../util/LinkageChart";
import { chartApiBar, remoteChartApi,chartBIanalysis } from "@/api/tool/datav/chartApi";

import { addOption } from "../../codegen/codegen";

import { barBIanalysis } from "@/api/tool/datav/chartBI/chartBarBI";
import { getFormsource } from "@/api/tool/datav/formsource";

const animationDuration = 6000;
import VueEvent from "@/views/tool/datav/VueEvent";
import { websocketCommand } from "../../util/websocket.js";

export default {
  mixins: [resize,interactConfig],
  props: {
    className: {
      type: String,
      default: "chart"
    },
    width: {
      type: String,
      default: "100%"
    },
    height: {
      type: String,
      default: "100%"
    },
    chartOption: {
      type: Object
    },
    drawingList: {
      type: Array
    }
  },
  data() {
    return {
      chart: null,
      //dataOption: this.chartOption,
      timer: "",
      wsObj: null,
      wsFlag: false,
      wsTimer: "",
      wsValue: null,
      animate: this.className
    };
  },
  watch: {
    width() {
      this.$nextTick(() => {
        this.chart.resize();
      });
    },
    height() {
      this.$nextTick(() => {
        this.chart.resize();
      });
    },
    chartOption: {
      deep: true,
      handler(newVal) {
        this.$nextTick(() => {
          this.setOptions(JSON.parse(JSON.stringify(newVal)));
        });
      }
    },
    // "chartOption.interactData": {
    //   handler(newVal) {

    //     console.log(newVal)

    //     if(newVal != undefined && newVal != ""){
    //       this.interactChart = this.chart;
          
    //       this.chartDiv = this.$refs.chartDiv;
    //       this.interactOption =this.option;
    //       this.interactData = newVal;

    //       this.runcode();
        
    //     }
    
    //   }
    // },
    "chartOption.theme": {
      handler() {
        if (this.chart != null) {
          this.chart.dispose();
          this.chart = null;
          this.initChart();
        }
      }
    },
    "chartOption.timeout": {
      handler() {
        this.chart.dispose();
        this.chart = null;
        this.initChart();
      }
    },
    "chartOption.dataSourceType": {
      handler(value) {
        //切换数据源重新连接
        if (value !== "websocket") {
          this.wsFlag = false;
          //每次切换数据源恢复原来动画
          this.animate = this.className;
        }
        if (value !== "url") {
          clearTimeout(this.timer);
        } 
      }
    },
    "chartOption.interfaceKey": {
      handler(newValue, oldValue) {
        //初始化不创建连接，改变接口地址重新创建
        if (oldValue !== undefined && oldValue != "") {
          this.wsValue = null;
          this.closeWs();
          this.createWs();
          this.animate = this.className;
        }
      }
    },
    wsFlag: {
      handler(value) {
        if (!value) {
          this.wsValue = null;
          this.closeWs();
        }
      }
    },
    className: {
      handler(value) {
        this.animate = value;
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initChart();
    });
  },
  beforeDestroy() {
    if (!this.chart) {
      return;
    }
    this.chart.dispose();
    this.chart = null;
    clearTimeout(this.timer);
    if (this.wsFlag) {
      this.closeWs();
    }
  },
  methods: {
    initChart() {
      echarts.registerTheme("customTheme", this.chartOption.theme);
      this.chart = echarts.init(this.$el, "customTheme");
      //判断是否开启定时器，当是访问url接口时候并且timeout不为0时候开启定时器
      if (this.timer != "") {
        clearTimeout(this.timer);
      }
      if (
        (this.chartOption.dataSourceType == 'url' || this.chartOption.dataSourceType == 'database') &&
        this.chartOption.timeout > 0
      ) {
        let timerTask = () => {
          this.setOptions(JSON.parse(JSON.stringify(this.chartOption)));
          this.timer = setTimeout(() => {
            timerTask();
          }, this.chartOption.timeout);
        };

        timerTask();
      }else{
        this.setOptions(JSON.parse(JSON.stringify(this.chartOption)));
      }
    },
    setOptions: async function(dataOption) {
      // console.log("=>",dataOption)

      //初始化数据
      //判断数据源
      if (dataOption.dataSourceType == "url") {
        let paramJson = parseQueryString(dataOption.requestParameters);
        //let interfaceURL = 'http://localhost:8088/chart/api/bar';
        let interfaceURL = dataOption.interfaceURL;
        
        dataOption.staticDataValue = await chartApiBar(
          dataOption.requestMethod,
          interfaceURL,
          paramJson,
          dataOption.token
        );

        //先判断输入的url是否合法
        // if(fIsUrL(dataOption.interfaceURL)) {
        //   try {
        //     //ajax请求
        //     var paramJson = parseQueryString(dataOption.requestParameters);
        //   } catch (error) {

        //   }
        // }

        //console.log(paramJson);
      } else if (dataOption.dataSourceType == "database") {
        if (
          dataOption.database.executeSql != undefined &&
          dataOption.database.executeSql != ""
        ) {
          let result = [];
          if(dataOption.database.sqlType != 'custom'){
          
            result = await barBIanalysis(dataOption.database);
          }else{
            result = await chartBIanalysis(dataOption.database);
          }
          if (result.code == 200) {
            dataOption.staticDataValue = result.data;
            //console.log(dataOption.staticDataValue);
          } else {
            alert("操作数据库错误");
          }
        }
      } else if (dataOption.dataSourceType == "form") {
        if (dataOption.formSource != undefined) {
          
          let response = await getFormsource(dataOption.formSource.id);
          dataOption.staticDataValue = JSON.parse(response.data.formData);
        }
      } else if (dataOption.dataSourceType == "websocket") {
        if (dataOption.interfaceKey != undefined &&dataOption.interfaceKey != "") {
          if (!this.wsFlag) {
            this.wsFlag = true;
            this.wsValue = null;
            this.createWs();
          }
          if (this.wsValue != null) {
            dataOption.staticDataValue = this.wsValue;
          }
        }
      }

      if (dataOption.animate != null) {
        //添加动画样式
        //animateUtil.addAnimate(dataOption.bindingDiv, dataOption.animate);
      }

      //数据格式转化
      if(dataOption.newDataFormat == true && !(dataOption.dataSourceType == 'database' && dataOption.bi != null)){
        
        let sortData = dealWithData(dataOption.staticDataValue,'type');
        let staticValue = [];
        for (const dt of sortData) {
          let data = [];
          let axisDATA = [];
          for (const d of dt.data) {
            data.push(d.value);
            axisDATA.push(d.name);
          }
          staticValue.push({"name":dt.type,"data":data,"axisData":axisDATA})
        }
        dataOption.staticDataValue = staticValue

        
      }
      
      var seriesData = [];
      var axisData = dataOption.staticDataValue[0].axisData;
      dataOption.xAxis.data = axisData;
      for (const value of dataOption.staticDataValue) {
        var data = {};
        data.type = "bar";
        data.name = value.name;
        data.barWidth = dataOption.barWidth; // 柱图宽度
        //data.stack = dataOption.stack;
        if (dataOption.stack == true) {
          data.stack = "sum";
        } else if (dataOption.stack == false) {
          data.stack = "";
        }

        //是否显示平均线
        if (dataOption.isMarkLine == true) {
          data.markLine = {
            data: [{ type: "average", name: "平均值" }]
          };
        } else if (
          dataOption.isMarkLine == false ||
          dataOption.isMarkLine == undefined
        ) {
          data.markLine = {};
        }

        //是否显示最大值和最小值
        if (dataOption.isMarkPoint == true) {
          data.markPoint = {
            data: [
              { type: "max", name: "最大值" },
              { type: "min", name: "最小值" }
            ]
          };
        } else if (
          dataOption.isMarkPoint == false ||
          dataOption.isMarkPoint == undefined
        ) {
          data.markPoint = {};
        }

        let raduis = dataOption.radius==undefined?12:dataOption.radius

        let barBorderRadius = [];

        //data.itemStyle = dataOption.itemStyle;
        //设置圆角样式
        if (dataOption.itemStyle == true) {
          
          //非竖显示
          if(!dataOption.isVertical){
            //半角
            if(dataOption.radiusType == "half"){
              barBorderRadius = [raduis, raduis, 0, 0]
            }
            //圆角
            else{
              barBorderRadius = raduis
            }
          }else{
            //半角
            if(dataOption.radiusType == "half"){
              barBorderRadius = [0, raduis, raduis, 0]
            }
            //圆角
            else{
              barBorderRadius =  raduis
            }
          }

          data.itemStyle = {
            
              //柱形图圆角，初始化效果 barBorderRadius:[12, 12, 12, 12]
              barBorderRadius: barBorderRadius
            
          };
        } else if (dataOption.itemStyle == false) {
          data.itemStyle = { emphasis: {} };
        }

        data.data = value.data;

        //设置柱体内标签
        if(dataOption.isLabel != undefined){
          data.label = {
            show: dataOption.isLabel == undefined?false:dataOption.isLabel,
            position: dataOption.labelPosition,
            distance: dataOption.labelDistance,
            align: 'left',
            verticalAlign: 'middle',
            rotate: dataOption.isVertical == true?0:90,
            formatter: '{c}  {name|{a}}',
            fontSize: dataOption.labelFontSize,
            color: dataOption.labelFontColor,
            rich: {
              name: {
                color: dataOption.labelFontColor,
                fontSize: dataOption.labelFontSize,
              }
            }
          }
        }
        
        seriesData.push(data);
      }

      var xAxisTemp, yAxisTemp;
      xAxisTemp = dataOption.xAxis;
      yAxisTemp = dataOption.yAxis;
      //是否竖显示
      if (dataOption.isVertical) {
        xAxisTemp = dataOption.yAxis;
        yAxisTemp = dataOption.xAxis;
      }
      //设置重叠柱图
      if(dataOption.gap){
        let z = 0;
        seriesData.forEach(element => {
          element.barGap =  '-100%'
          element.z = z++
        });
      }

      //设置分隔线样式
      if(dataOption.yAxis.splitLine.show){

        let splitLineStyle = {
          color:dataOption.splitLineColor == undefined? '#ccc':dataOption.splitLineColor,
          width:dataOption.splitLineWidth == undefined? 1:dataOption.splitLineWidth,
          type: dataOption.lineStyle == undefined? 'solid':dataOption.lineStyle,
        }
        //根据是否竖显示，设置x轴或者y轴分隔线
        if(yAxisTemp.splitLine != undefined){
          yAxisTemp.splitLine.lineStyle = splitLineStyle
        }else{
          xAxisTemp.splitLine.lineStyle = splitLineStyle
        }

      }

      
      let axisTick = {
        show : false
      };

      //设置X轴Y轴刻度不显示
      xAxisTemp.axisTick = axisTick;
      

      let xlineStyle = {
          color: typeof(dataOption.xLineColor)=="undefined"?"#fff":(dataOption.xLineColor == null?"transparent":dataOption.xLineColor),
          width: dataOption.xLineWidth == undefined ? 1:dataOption.xLineWidth,
          
      }

      //设置X轴标签样式
      let xAxisLabel = {
          textStyle: {
            show:true,
            color: typeof(dataOption.xFontColor)=="undefined"?"#fff":(dataOption.xFontColor == null?"transparent":dataOption.xFontColor),
            fontSize: dataOption.xFontSize==undefined?14:dataOption.xFontSize,
          },                           
      }
      xAxisTemp.axisLabel = xAxisLabel;
      xAxisTemp.axisLine.lineStyle = xlineStyle;
      xAxisTemp.axisLine.show = dataOption.xLineShow;

      //设置坐标轴名称样式
      xAxisTemp.nameTextStyle = {
        color : dataOption.xFontColor,
        fontSize : dataOption.xFontSize
      }


      //设置y轴样式
      yAxisTemp.axisTick = axisTick;
      let ylineStyle = {
          color: typeof(dataOption.yLineColor)=="undefined"?"#fff":(dataOption.yLineColor == null?"transparent":dataOption.yLineColor),
          width: dataOption.yLineWidth == undefined ? 1:dataOption.yLineWidth,
          
      }

      //设置X轴标签样式
      let yAxisLabel = {
          textStyle: {
            show:true,
            color: typeof(dataOption.yFontColor)=="undefined"?"#fff":(dataOption.yFontColor == null?"transparent":dataOption.yFontColor),
            fontSize: dataOption.yFontSize==undefined?14:dataOption.yFontSize,
          },                           
      }
      yAxisTemp.axisLabel = yAxisLabel;
      yAxisTemp.axisLine.lineStyle = ylineStyle;
      yAxisTemp.axisLine.show = dataOption.yLineShow;

      //设置坐标轴名称样式
      yAxisTemp.nameTextStyle = {
        color : dataOption.yFontColor,
        fontSize : dataOption.yFontSize
      }

      //图例
      let legendData={
        //  data:legend,
         show:dataOption.legend.show,
           x : (dataOption.legendX || 35)+'%',
           y : (dataOption.legendY || 5) +'%',
        orient:dataOption.legendOrient==undefined?"horizontal":dataOption.legendOrient,
        textStyle:{
          fontSize : dataOption.legendFontSize==undefined?"14":dataOption.legendFontSize,
          color : dataOption.legendFontColor==undefined?"#fff":dataOption.legendFontColor
        },
        itemWidth : dataOption.itemWidth || 14,
        itemHeight : dataOption.itemHeight || 8
      };

      let dataZoom = {
          type: dataOption.dataZoomType, //  dataOption.dataZoomType,
          show: dataOption.dataZoomShow != true ? false : true,
          start: dataOption.dataZoomStart,
          end: dataOption.dataZoomEnd,
          handleSize: dataOption.handleSize,
          textStyle:{
            color: dataOption.dataZoomFontColor,
            fontSize:dataOption.dataZoomFontSize
          }
        };
      let dataZoomArr = [];
      if(dataOption.axis != undefined && dataOption.axis.length > 0){
        dataOption.axis.forEach(element => {
          let data = JSON.parse(JSON.stringify(dataZoom))
          if(element == "x轴"){
            data.xAxisIndex = 0
            data.bottom = '0%'
          }else{
            data.yAxisIndex = 0
            data.right = '4%'
          }
          dataZoomArr.push(data)
        });
      }

      let option = {
        title: dataOption.title,
        tooltip: dataOption.tooltip,
        legend: legendData,
        grid: {
          top: "25%",
          left: "2%",
          right: "10%",
          bottom: "3%",
          containLabel: true
        },
        xAxis: xAxisTemp,
        yAxis: yAxisTemp,
        series: seriesData
      };

      if(dataOption.dataZoomShow){
        option.dataZoom = dataZoomArr;
      }

      //执行通用处理函数
      if(dataOption.customData != undefined && dataOption.customData != ""){
        
        try {
          option = (
          
            //里面为要处理的代码块
          eval(dataOption.customData) 
          
          )(
            option,
            dataOption.staticDataValue,
            this.$refs.chartDiv
          );
        } catch (error) {
          console.log(error)
        }
        
       }      
        //交互组件配置
      if(dataOption.interactData != undefined && dataOption.interactData != ""){
          try {
              option = (        
              //里面为要处理的代码块
              eval(dataOption.interactData)             
            )(
            option,
            dataOption.staticDataValue,
            this.$refs.chartDiv
            );
          } catch (error) {
            console.log(error)
          }               
       }

      this.chart.setOption(option, true);

      addOption(dataOption.bindingDiv, option);
      //开启图表联动
      if (dataOption.isLink == true) {
        this.chart.off("click");
        this.chart.on("click", params => {
          //设置参数
          let arrObject = {
            legendName: params.name,
            seriesName: params.seriesName,
            data: params.value
          };

          let arrs = JSON.stringify(arrObject);

          //获取绑定的图表
          let bindList = this.chartOption.bindList;

          if (bindList.length > 0) {
            linkChart(dataOption.arrName, arrs, bindList, this.drawingList);
          }
        });
      }
      // else{
      //   //关闭图表联动，取消echart点击事件
      //   this.chart.off('click');
      // }

      //开启图表下钻
      else if (dataOption.isDrillDown == true) {
        this.chart.off("click");
        this.chart.on("click", params => {
          //设置参数
          let arrObject = {
            legendName: params.name,
            seriesName: params.seriesName,
            data: params.value
          };

          let arrs = JSON.stringify(arrObject);

          //获取绑定的图表
          let drillDownChartOption = this.chartOption.drillDownChartOption;

          if (
            drillDownChartOption != undefined &&
            drillDownChartOption != null
          ) {
            this.$set(
              this.chartOption.drillDownChartOption.chartOption,
              "requestParameters",
              "drillParam=" + arrs
            );
            //发送下钻消息
            VueEvent.$emit(
              "drill_down_msg",
              this.chartOption.drillDownChartOption
            );
          }
        });
      } else {
        //关闭图表联动，取消echart点击事件
        this.chart.off("click");
      }
      // this.chart.getZr().off('click');
      // this.chart.getZr().on('click',(params) => {
      //   let point=[params.offsetX,params.offsetY];
      //   if(this.chart.containPixel('grid',point)){
      //       let xIndex=this.chart.convertFromPixel({seriesIndex:0}, point)[0];

      //       let op=this.chart.getOption();
      //       let name=op.xAxis[0].data[xIndex];

      //   }

      // })
      if (dataOption.isRemote == true) {
        if (dataOption.remote != undefined && dataOption.remote != null) {
          this.chart.off("click");
          this.chart.on("click", params => {
            //设置参数
            let arrObject = {
              legendName: params.name,
              seriesName: params.seriesName,
              data: params.value
            };

            let remoteData = { ...dataOption.remote };
            remoteData.query = arrObject;
            //调用接口
            remoteChartApi(remoteData);

          });
        }

      }
    },
    //  ws连接成功，后台返回的ws数据
    receiveMsg(e) {
      if (e.action == "chat") {
        // console.log('服务端推送',e);
        this.wsValue = JSON.parse(e.result);
        this.setOptions(JSON.parse(JSON.stringify(this.chartOption)));
      }
    },
    // 建立连接、发起ws请求，以心跳方式，向服务端发送数据
    createWs() {
      this.wsObj = new WebSocket(process.env.VUE_APP_WEBSOCKET);
      // 若为对象类型，以回调方式发送
      websocketCommand(
        this.wsObj,
        "create",
        5000,
        this.chartOption.interfaceKey,
        this.sendHeartBeat,
        this.receiveMsg,
        this.reconnectWs,
        this.wsWarning
      );
    },
    // 断网重连，需要处理的逻辑
    reconnectWs() {
      if (this.wsObj) {
        console.log("%c websocket_reconnect", "color:blue");
        this.createWs();
      }
    },
    // 以回调方式向服务端发送(对象类型的)心跳
    sendHeartBeat() {
      if (this.wsTimer != "") {
        clearTimeout(this.wsTimer);
      }

      let wsTimerTask = () => {
        console.log("发送心跳", "ping");
        let obj = { action: "keep", key: this.chartOption.interfaceKey };
        this.wsObj.send(JSON.stringify(obj));
        this.wsTimer = setTimeout(() => {
          wsTimerTask();
        }, parseInt(process.env.VUE_APP_WEBSOCKET_TIMEOUT));
        this.wsWarning();
      };
      wsTimerTask();
    },

    wsWarning() {
      //如果断开连接则显示组件警告动画并清除计数器
      if (this.wsObj.readyState == 3) {
        this.animate = "warning";
        clearTimeout(this.wsTimer);
      }
    },
    closeWs() {
      clearTimeout(this.wsTimer);
      websocketCommand(
        this.wsObj,
        "close",
        5000,
        this.chartOption.interfaceKey,
        this.sendHeartBeat,
        this.receiveMsg,
        this.reconnectWs,
        this.wsWarning
      );
      this.wsObj = null;
    },
  
  }
};
</script>
